package cn.xp1997.shiro.x.security;

import cn.xp1997.shiro.x.exception.AuthenticationAuthorizationInfoException;
import cn.xp1997.shiro.x.info.AuthenticationAuthorizationInfo;
import cn.xp1997.shiro.x.realm.RealmX;
import cn.xp1997.shiro.x.subject.SubjectFactoryX;
import cn.xp1997.shiro.x.token.TokenFactory;
import cn.xp1997.shiro.x.utils.ShiroUtil;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SessionStorageEvaluator;
import org.apache.shiro.mgt.SubjectDAO;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;

import java.util.ArrayList;
import java.util.List;


/**
 * 自定义安全管理器
 * @author xp
 */
public class SecurityManagerX extends DefaultWebSecurityManager {




    private SubjectFactoryX subjectFactory;

    private RealmX realmX;

    private List<AuthenticationAuthorizationInfo> authenticationAuthorizationInfos;


    /**
     * 安全管理器构筑器
     */
    public SecurityManagerX(){
        //初始化安全管理器
        initSecurityManage();
    }

    /**
     * 初始化安全管理器
     */
    private void initSecurityManage(){
        //创建subjectDao 禁用session
        setSubjectDAO(createSubjectDAO());
        //创建realm
        setRealm(createRealmX());
        initShiroUtil();
        initSubjectFactory();
    }

    private void initShiroUtil(){
        ShiroUtil.securityManagerX = this;
        ShiroUtil.tokenFactory = new TokenFactory();
    }

    public void initSubjectFactory(){
        this.subjectFactory = new SubjectFactoryX();
    }

    public SubjectFactoryX getSubjectFactoryX(){
        return this.subjectFactory;
    }

    /**
     * 设置realm
     */
    private void setRealmX(RealmX realmX){
        this.realmX = realmX;
    }

    private RealmX getRealmX(){
        return this.realmX;
    }

    /**
     * 设置认证授权信息列表
     * @param authenticationAuthorizationInfos 认证授权信息列表
     */
    public void setAuthenticationAuthorizationInfos(List<AuthenticationAuthorizationInfo> authenticationAuthorizationInfos){
        if(null == authenticationAuthorizationInfos || authenticationAuthorizationInfos.size() == 0){
            throw new AuthenticationAuthorizationInfoException("no AuthenticationAuthorizationInfo found");
        }
        this.authenticationAuthorizationInfos = authenticationAuthorizationInfos;
        //将认证授权信息放入realm中 供realm使用
        getRealmX().setAuthenticationAuthorizationInfos(getAuthenticationAuthorizationInfos());
    }

    /**
     * 设置单个认证授权信息
     * @param authenticationAuthorizationInfo 认证授权信息
     */
    public void setAuthenticationAuthorizationInfo(AuthenticationAuthorizationInfo authenticationAuthorizationInfo){
        if(null == authenticationAuthorizationInfo ){
            throw new AuthenticationAuthorizationInfoException("authenticationAuthorizationInfo can not be null");
        }
        //如果认证授权信息列表不存在则创建新的列表
        if(null == getAuthenticationAuthorizationInfos()){
            this.authenticationAuthorizationInfos = new ArrayList<>();
        }

        getAuthenticationAuthorizationInfos().add(authenticationAuthorizationInfo);
        //将认证授权信息放入realm中 供realm使用
        getRealmX().setAuthenticationAuthorizationInfos(getAuthenticationAuthorizationInfos());
    }

    /**
     * 获取 authenticationAuthorizationInfo
     * @return authenticationAuthorizationInfo
     */
    private List<AuthenticationAuthorizationInfo> getAuthenticationAuthorizationInfos(){
        return this.authenticationAuthorizationInfos;
    }

    /**
     * 禁用session, 不保存用户登录状态。保证每次请求都重新认证
     */
    private SubjectDAO createSubjectDAO(){
        DefaultSubjectDAO defaultSubjectDAO = new DefaultSubjectDAO();
        defaultSubjectDAO.setSessionStorageEvaluator(createSessionStorageEvaluator());
        return defaultSubjectDAO;
    }


    /**
     * 将sessionStorageEvaluator放入subjectDAO中才会生效
     */
    private SessionStorageEvaluator createSessionStorageEvaluator() {
        DefaultSessionStorageEvaluator sessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        sessionStorageEvaluator.setSessionStorageEnabled(false);
        return sessionStorageEvaluator;
    }

    /**
     * 创建realm
     */
    private RealmX createRealmX() {
        RealmX realmX = new RealmX();
        setRealmX(realmX);
        return realmX;
    }

}
